// 给定一个只包含 '(' 和 ')' 的字符串，找出最长的包含有效括号的子串的长度。

// 示例 1:

// 输入: "(()"
// 输出: 2
// 解释: 最长有效括号子串为 "()"
// 示例 2:

// 输入: ")()())"
// 输出: 4
// 解释: 最长有效括号子串为 "()()"

#include <string>
#include <stack>
#include <vector>

using namespace std;

// 栈
// 时间复杂度：O(N)
// 空间复杂度：O(N)
class Solution {
public:
    int longestValidParentheses(string s) {
        int res{0};
        stack<int> stk{};
        stk.push(-1);
        for (int i{0}, n = s.size(); i < n; ++i) {
            if (s[i] == '(') stk.push(i);
            else {
                stk.pop();
                if (stk.empty()) {
                    stk.push(i); // 最后一个没有被匹配的右括号的下标
                } else { // 以该右括号为结尾的最长有效括号的长度
                    res = max(res, i - stk.top());
                }
            }
        }
        return res;
    }
};

// 双指针，双向遍历
// 时间复杂度：O(N)
// 空间复杂度：O(1)
class Solution {
public:
    int longestValidParentheses(string s) {
        int left{0};
        int right{0};
        int res{0};
        int n = s.size();
        for (int i{0}; i < n; ++i) { // (() 这样的情况无法解决
            if (s[i] == '(') ++left;
            else ++right;
            if (left == right) res = max(res, 2 * left);
            else if (right > left) left = right = 0;
        }
        left = right = 0;
        for (int i{n - 1}; i >= 0; --i) {
            if (s[i] == '(') ++left;
            else ++right;
            if (left == right) res = max(res, 2 * left);
            else if (left > right) left = right = 0;
        }
        return res;
    }
};

// 动态规划
// 时间复杂度：O(N)
// 空间复杂度：O(N)
class Solution {
public:
    int longestValidParentheses(string s) {
        int res{0};
        int n = s.size();
        vector<int> dp(n, 0);
        for (int i{1}; i < n; ++i) {
            if (s[i] == ')') {
                if (s[i-1] == '(') {
                    dp[i] = (i >= 2 ? dp[i-2] : 0) + 2;
                } else if (i - dp[i-1] > 0 && s[i - dp[i-1] - 1] == '(') {
                    dp[i] = dp[i-1] + ((i - dp[i-1]) >= 2 ? dp[i - dp[i-1] - 2] : 0) + 2;
                }
                res = max(res, dp[i]);
            }
        }
        return res;
    }
};
